﻿#include "Root.h"

bool IsTextUTF8(const std::string& str)
{
	char nBytes = 0;//UFT8可用1-6个字节编码,ASCII用一个字节
	unsigned char chr;
	bool bAllAscii = true; //如果全部都是ASCII, 说明不是UTF-8

	for (int i = 0; i < str.length(); i++)
	{
		chr = str[i];

		// 判断是否ASCII编码,如果不是,说明有可能是UTF-8,ASCII用7位编码,
		// 但用一个字节存,最高位标记为0,o0xxxxxxx
		if ((chr & 0x80) != 0)
			bAllAscii = false;

		if (nBytes == 0) //如果不是ASCII码,应该是多字节符,计算字节数
		{
			if (chr >= 0x80)
			{
				if (chr >= 0xFC && chr <= 0xFD)   nBytes = 6;
				else if (chr >= 0xF8)         nBytes = 5;
				else if (chr >= 0xF0)         nBytes = 4;
				else if (chr >= 0xE0)         nBytes = 3;
				else if (chr >= 0xC0)         nBytes = 2;
				else {
					return false;
				}
				nBytes--;
			}
		}
		else //多字节符的非首字节,应为 10xxxxxx
		{
			if ((chr & 0xC0) != 0x80) {
				return false;
			}
			nBytes--;
		}
	}

	if (nBytes > 0) //违返规则
		return false;

	if (bAllAscii) //如果全部都是ASCII, 说明不是UTF-8
		return false;

	return true;
}

// 回调函数
int callback(void* data, int argc, char** argv, char** azColName) {
	vector<Role>* vroles = static_cast<std::vector<Role>*>(data);
	Role vrole;
	//cout << argv[0] << argv[1] << argv[2] << endl;
	// 假设表中有三列：id, name, position
	vrole.id = std::stoi(argv[0]);
	vrole.admin = argv[1] ? RoleBaseClass::UTF8ToString(argv[1]) : "";
	vrole.password = argv[2] ? argv[2] : "";

	// 将结构体实例添加到动态数组中
	vroles->push_back(vrole);

	return 0; // 继续处理下一行
}

//菜单
void Root::ShowMenu()
{
	int count;
	while (true)
	{
		cout << endl << endl << endl;
		cout << "欢迎管理员：" << this->getUserName() << "登录！" << endl;
		cout << "\t\t ---------------------------------\n";
		cout << "\t\t|                                |\n";
		cout << "\t\t|          1.添加账号            |\n";
		cout << "\t\t|                                |\n";
		cout << "\t\t|          2.查看账号            |\n";
		cout << "\t\t|                                |\n";
		cout << "\t\t|          3.查看机房            |\n";
		cout << "\t\t|                                |\n";
		cout << "\t\t|          4.清空预约            |\n";
		cout << "\t\t|                                |\n";
		cout << "\t\t|          0.注销登录            |\n";
		cout << "\t\t|                                |\n";
		cout << "\t\t ---------------------------------\n";
		cout << "请选择您的操作： " << endl;

		cin >> count;
		switch (count)
		{
		case 1:
			this->AddRole();
			break;
		case 2:
			this->ShowPerson();
			break;
		case 3:
			this->ShowRoom();
			break;
		case 4:
			this->ClearOrder();
			break;
		case 0:
			return;
			break;
		default:
			break;
		}
		//system("cls");
	}
}

//添加用户
void Root::AddRole()
{
	//要添加账户的种类
	int type;
	cout << "请输入代表角色的种类代号" << endl;
	cout << "1、学生" << endl;
	cout << "2、教师" << endl;
	//
	cin >> type;
	//判断种类，去访问不同的表
	//创建变量去接用户输入的内容
	int userId;
	string admin;
	string password;
	cout << "依次输入id,admin,password"<<endl;
	
	cin >> userId >> admin >> password;

	if (1 == type)
	{
		//创建学生
		// 打开数据库
		sqlite3* sql = NULL; // 一个打开的数据库实例
		const char* path = "./RoomReservation.db";//某个sql文件的路径
		int result = sqlite3_open_v2(path, &sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL);
		if (result == SQLITE_OK) {
			//cout << "打开数据库连接成功" << endl;
		}
		else {
			//cout << "打开数据库连接失败" << endl;
		}
		//组成sql语句，先去查询是否有该学生id存在，若存在，则不进行创建。若不存在则将信息传入表创建
		sqlite3_stmt* stmt;
		const char* sqlsel = "select * from EndUser where id =  ?";
		int ret = sqlite3_prepare_v2(sql, sqlsel, -1, &stmt, NULL);
		if (SQLITE_OK != ret)
		{
			cout << __FILE__ << __LINE__ << "ERR" << endl;
		}
		//绑定参数
		sqlite3_bind_int(stmt, 1, userId);
		//执行查询
		ret = sqlite3_step(stmt);
		//判断查询结果
		if (SQLITE_ROW != ret)
		{
			//查询不存在，可以插入
			//cout << "查询不存在" << endl;
			//组建sql语句进行插入
			//insert into EndUser(id,admin,password) values(2,'name2','pass2');
			const char* sqlins = u8"insert into EndUser(id,admin,password) values(?,?,?);";
			ret = sqlite3_prepare_v2(sql, sqlins, -1, &stmt, NULL);
			if (SQLITE_OK != ret)
			{
				cout << __FILE__ << __LINE__ << "ERR" << endl;
			}
			sqlite3_bind_int(stmt, 1, userId);
			//sqlite3_bind_text 的第三个参数是指向要绑定的字符串的指针，
			// 第四个参数是字符串的长度（如果设置为-1，则SQLite会自动计算长度），
			// 第五个参数是数据的存储类别，这里使用SQLITE_TRANSIENT 表示SQLite在不需要时可以安全地丢弃这个字符串。

			string admintemp = string_To_UTF8(admin);

			sqlite3_bind_text(stmt, 2, admintemp.c_str(), -1, SQLITE_STATIC);
			sqlite3_bind_text(stmt, 3, password.c_str(),-1, SQLITE_STATIC);

			ret = sqlite3_step(stmt);
			if (ret == SQLITE_DONE)
			{
				cout << "插入成功" << endl;
			}
			else
			{
				cout << "插入失败" << endl;
			}
		}
		else
		{
			cout << "该用户id已存在，返回管理员主菜单" << endl;
			return;
		}
		sqlite3_finalize(stmt);
		sqlite3_close(sql);
	}
	else if (2 == type)
	{
		//创建教师
		sqlite3* sql = NULL; // 一个打开的数据库实例
		const char* path = "./RoomReservation.db";//某个sql文件的路径
		int ret = sqlite3_open_v2(path, &sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL);
		/*if (ret == SQLITE_OK) {
			cout << "打开数据库连接成功" << endl;
		}
		else {
			cout << "打开数据库连接失败" << endl;
		}*/
		if (SQLITE_OK != ret)
		{
			cout << __FILE__ << __LINE__ << "ERR" << endl;
		}
		sqlite3_stmt* stmt;
		const char* sqlsel = "select * from Manager where id =  ?";
		ret = sqlite3_prepare_v2(sql, sqlsel, -1, &stmt, NULL);
		if (SQLITE_OK != ret)
		{
			cout << __FILE__ << __LINE__ << "ERR" << endl;
		}
		sqlite3_bind_int(stmt, 1, userId);
		ret = sqlite3_step(stmt);
		if (SQLITE_ROW != ret)
		{
			const char* sqlins = u8"insert into Manager(id,admin,password) values(?,?,?);";
			ret = sqlite3_prepare_v2(sql, sqlins, -1, &stmt, NULL);
			if (SQLITE_OK != ret)
			{
				cout << __FILE__ << __LINE__ << "ERR" << endl;
			}
			sqlite3_bind_int(stmt, 1, userId);
			string admintemp = string_To_UTF8(admin);

			sqlite3_bind_text(stmt, 2, admintemp.c_str(), -1, SQLITE_STATIC);
			sqlite3_bind_text(stmt, 3, password.c_str(), -1, SQLITE_STATIC);

			ret = sqlite3_step(stmt);
			if (ret == SQLITE_DONE)
			{
				cout << "插入成功" << endl;
			}
			else
			{
				cout << "插入失败" << endl;
			}
		}
		else
		{
			cout << "该用户id已存在，返回管理员主菜单" << endl;
			return;
		}
		sqlite3_finalize(stmt);
		sqlite3_close(sql);
	}
	else
	{
		cout << "输入有误，管理员主窗口" << endl;
		return;
	}
}

//查看用户信息
void Root::ShowPerson()
{
	//选择查看学生信息、教师信息
	cout << "请选择要查看的信息" << endl;
	cout << "1、学生" << endl;
	cout << "2、教师" << endl;
	//可以先打开数据库
	sqlite3* sql = NULL; 
	const char* path = "./RoomReservation.db";
	int ret = sqlite3_open_v2(path, &sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL);
	if (SQLITE_OK != ret)
	{
		cout << __FILE__ << __LINE__ << "ERR" << endl;
	}
	//创建一个动态数组准备存内容
	vector<Role> vRole;
	char* zErrMsg = 0;
	int type;
	cin >> type;
	if (1 == type)
	{
		//学生,
		const char* sqlsel = "select id,admin,password from EndUser";
		ret = sqlite3_exec(sql, sqlsel, callback, &vRole, &zErrMsg);

		//获取内容到动态数组后打印
		cout << "" << endl;
		cout << setw(3) << "id" << setw(10) << "姓名" << setw(20) << "密码" << endl;
		for (auto role : vRole)
		{
			cout << setw(3) << role.id << setw(10) << role.admin << setw(20) << role.password << endl;
		}

		//询问是否返回管理员主菜单
		cout << "是否返回主菜单" << endl;
		char temp = getchar();
	}
	else
	{
		//教师
		const char* sqlsel = "select id,admin,password from Manager";
		ret = sqlite3_exec(sql, sqlsel, callback, &vRole, &zErrMsg);

		//获取内容到动态数组后打印
		cout << "" << endl;
		cout << setw(3) << "id" << setw(10) << "姓名" << setw(20) << "密码" << endl;
		for (auto role : vRole)
		{
			cout << setw(3) << role.id << setw(10) << role.admin << setw(20) << role.password << endl;
		}

		//询问是否返回管理员主菜单
		cout << "是否返回主菜单" << endl;
	}

	sqlite3_close(sql);
	return;
}

//查看机房信息
void Root::ShowRoom()
{
	//打开数据库，
	sqlite3* sql = NULL;
	const char* path = "./RoomReservation.db";
	int ret = sqlite3_open_v2(path, &sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL);
	if (SQLITE_OK != ret)
	{
		cout << __FILE__ << __LINE__ << "ERR" << endl;
	}

	//组建sql语句
	const char* sqlsel = "select * from RoomInfo";
	char* errmsg;
	char** mResult;//结果集
	int mRow;//行数
	int mCol;//列数
	int nResult = sqlite3_get_table(sql, sqlsel, &mResult, &mRow, &mCol, &errmsg);

	int nIndex = mCol;
	cout << "mRow: " << mRow << endl;
	cout << "mCol: " << mCol << endl;
	
	vector<map<string, string>> vroom;
	if (mRow > 0 && mCol > 0)
	{
		//student stu;
		for (int i = 0; i < mRow; i++)
		{
			map<string, string> room;
			for (int j = 0; j < mCol; j++)
			{
				if (!strcmp("id", mResult[j]))
				{
					string id = mResult[nIndex];
					room.insert(make_pair("id", id));
				}
				else if (!strcmp("name", mResult[j]))
				{
					string name = UTF8ToString(mResult[nIndex]);
					room.insert(make_pair("name", name));
				}
				else if (!strcmp("capacity", mResult[j]))
				{
					string capacity = mResult[nIndex];
					room.insert(make_pair("capacity", capacity));
				}
				++nIndex;
			}
			vroom.push_back(room);
		}
		//使用完 sqlite3_get_table 后务必释放为记录分配的内存，否则会内存泄漏
		sqlite3_free_table(mResult);
	}
	//接，输出
	cout << "机房信息" << endl;
	cout <<setw(3)<< "id" <<setw(10)<< "name" <<setw(3)<< "容量" << endl;
	for (auto room : vroom)
	{
		cout << setw(3) << room["id"] << setw(10) << room["name"] << setw(3) << room["capacity"] << endl;
	}

	sqlite3_close(sql);
}

//清空记录
void Root::ClearOrder()
{
	//连数据库，
	sqlite3* sql = NULL;
	const char* path = "./RoomReservation.db";
	int ret = sqlite3_open_v2(path, &sql, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_SHAREDCACHE, NULL);
	if (SQLITE_OK != ret)
	{
		cout << __FILE__ << __LINE__ << "ERR" << endl;
	}
	//清空表
	char* errMsg = 0;
	//清空表内容，sqlite没有truncate table table_name;这条语句
	const char* sqldel = "delete from RoomOrderRecord";
	ret = sqlite3_exec(sql, sqldel, 0, 0, &errMsg);
	if (SQLITE_OK != ret)
	{
		cout << __FILE__ << __LINE__ << "清空失败"<<errMsg << endl;
	}

	sqlite3_close(sql);
}